"""模拟打印机问题
10个学生，一小时每人会发生2次左右的打印，每次1～20页
打印机：快速10页/分钟，高质量5页每分钟
"""
from pythonds.basic import Queue

import random


class Task:
    """打印任务的抽象"""

    def __init__(self, time):
        self.ctime = time  # 任务创建时间
        self.pages = random.randrange(1, 21)

    def wait_time(self, current_time) -> int:
        return current_time - self.ctime


def new_task():
    """模拟打印任务产生
    产生概率：
        10*2/3600 = 1/180,即平均180秒产生一个打印任务
    Returns:
        该时间点是否产生任务
    """
    return 180 == random.randrange(1, 181)


class Printer:
    """打印机的抽象"""

    def __init__(self, ppm):
        self.rate = ppm  # 打印速度
        self.cur_task = None  # 当前打印任务
        self.time_remaining = 0  # 任务倒计时

    # 　扫描周期
    def tick(self):
        if self.cur_task is not None:
            self.time_remaining = self.time_remaining - 1

            if self.time_remaining <= 0:
                self.cur_task = None

    def busy(self):
        return self.cur_task is not None

    def start_next(self, new_task: Task):
        self.cur_task = new_task
        self.time_remaining = new_task.pages * 60 / self.rate


def simulation(num_seconds: int, ppm):
    """利用队列模拟打印

    Args:
        num_seconds (int): 模拟时长（秒数）
        ppm (_type_): 打印速度（页/分钟）
    """
    printer = Printer(ppm)
    print_queue = Queue()
    waiting_times = []

    for cur_second in range(num_seconds):

        if new_task():
            task = Task(cur_second)
            print_queue.enqueue(task)

        if (not printer.busy()) and (not print_queue.empty()):
            next_task = print_queue.dequeque()
            waiting_times.append(next_task.wait_time(cur_second))
            printer.start_next(next_task)

        printer.tick()

    avg_wait = sum(waiting_times) / len(waiting_times)
    print(
        "Average Wait %4.2f sec, %d tasks remaining." % (avg_wait, print_queue.size())
    )
